# cron: 45 8,10,11,13,16,17,18,20,21,23 * * *
# new Env("河马剧场")
"""
本工具仅用于学习 Python 加密与逆向工程技术，供研究和教学用途。
请勿将其用于任何非法用途，包括但不限于： 加密恶意脚本 | 逃避安全审计 | 攻击他人系统 | 商业软件加壳绕过
任何使用本工具所造成的直接或间接后果，包括但不限于法律责任、安全问题、数据损失，均由使用者自行承担，作者不对此承担任何责任。
如果您不同意此免责声明，请立即停止使用并删除本文件。

Developed by Python Vorto加密系统

所需要的变量名称及格式，请运行脚本查看！
"""
import os
import sys
import hashlib
import json
import importlib.util
from pathlib import Path
from typing import Optional, Dict, Any

# 配置（请勿修改）
PROJECT_ID = "a711a699-0f07-4773-a866-9ced2f875cd9"
BASE_URL = "https://so.vorto.cc"
SO_FILENAME = "S_HMJC"
VERSION_FILE = ".{0}_version.json".format("S_HMJC")
ENTRY_FUNCTION = "main"


def get_python_version() -> str:
    return "{0}.{1}".format(sys.version_info.major, sys.version_info.minor)


def calculate_md5(file_path: str) -> str:
    """计算文件的MD5哈希值"""
    md5_hash = hashlib.md5()
    try:
        with open(file_path, "rb") as f:
            for chunk in iter(lambda: f.read(4096), b""):
                md5_hash.update(chunk)
        return md5_hash.hexdigest()
    except Exception as ex:
        print("计算MD5失败: {0}".format(ex))
        return ""


def load_local_version() -> Optional[Dict[str, Any]]:
    """加载本地版本信息"""
    if not os.path.exists(VERSION_FILE):
        return None
    
    try:
        with open(VERSION_FILE, 'r', encoding='utf-8') as f:
            return json.load(f)
    except Exception as ex:
        print("读取本地版本信息失败: {0}".format(ex))
        return None


def save_local_version(version_info: Dict[str, Any]):
    """保存本地版本信息"""
    try:
        with open(VERSION_FILE, 'w', encoding='utf-8') as f:
            json.dump(version_info, f, indent=2, ensure_ascii=False)
    except Exception as ex:
        print("保存版本信息失败: {0}".format(ex))


def check_server_version() -> Optional[Dict[str, Any]]:
    """检查服务器上的活跃版本信息"""
    try:
        import urllib.request
        import urllib.error
        
        url = "{0}/api/version/{1}".format(BASE_URL, PROJECT_ID)
        
        try:
            with urllib.request.urlopen(url, timeout=10) as response:
                data = response.read()
                return json.loads(data.decode('utf-8'))
        except urllib.error.HTTPError as ex:
            if ex.code == 404:
                print("项目不存在或没有活跃版本")
            else:
                print("查询版本失败 (HTTP {0}): {1}".format(ex.code, ex.reason))
            return None
        except urllib.error.URLError as ex:
            print("网络连接失败: {0}".format(ex.reason))
            return None
            
    except ImportError:
        print("urllib模块不可用，无法检查更新")
        return None
    except Exception as ex:
        print("检查服务器版本失败: {0}".format(ex))
        return None


def download_so_file(version_info: Dict[str, Any]) -> bool:
    """下载SO文件"""
    try:
        import urllib.request
        
        python_ver = get_python_version()
        version_id = version_info['version_id']
        
        # 构建下载URL
        url = "{0}/api/download/{1}/{2}/{3}".format(BASE_URL, PROJECT_ID, version_id, python_ver)
        
        # 确定SO文件名（包含Python版本）
        so_file = "{0}_{1}.so".format(SO_FILENAME, python_ver.replace('.', ''))
        
        print("正在下载版本 {0}...".format(version_info['version_number']))
        
        # 下载文件
        urllib.request.urlretrieve(url, so_file)
        
        # 验证文件完整性（使用对应Python版本的MD5）
        md5_hashes = version_info.get('md5_hashes', {})
        expected_md5 = md5_hashes.get(python_ver)
        
        if expected_md5:
            local_md5 = calculate_md5(so_file)
            if local_md5 != expected_md5:
                print("警告: 文件MD5校验失败")
                print("  期望: {0}".format(expected_md5))
                print("  实际: {0}".format(local_md5))
                os.remove(so_file)
                return False
            print("MD5校验通过")
        
        # 保存版本信息
        save_local_version(version_info)
        
        print("下载完成: {0}".format(so_file))
        return True
        
    except Exception as ex:
        print("下载SO文件失败: {0}".format(ex))
        return False


def need_update(local_version: Optional[Dict[str, Any]], server_version: Optional[Dict[str, Any]]) -> bool:
    """判断是否需要更新"""
    if server_version is None:
        # 服务器没有活跃版本
        return False
    
    if local_version is None:
        # 本地没有版本信息
        return True
    
    # 比较version_id
    if local_version.get('version_id') != server_version.get('version_id'):
        return True
    
    # 检查SO文件是否存在
    python_ver = get_python_version()
    so_file = "{0}_{1}.so".format(SO_FILENAME, python_ver.replace('.', ''))
    if not os.path.exists(so_file):
        return True
    
    return False


def load_so_module():
    """加载SO模块"""
    python_ver = get_python_version()
    so_file = "{0}_{1}.so".format(SO_FILENAME, python_ver.replace('.', ''))
    
    # 检查本地版本
    local_version = load_local_version()
    
    # 检查服务器版本
    server_version = check_server_version()
    
    # 判断是否需要更新
    if need_update(local_version, server_version):
        if server_version:
            print("发现新版本: {0}".format(server_version['version_number']))
            if not download_so_file(server_version):
                if not os.path.exists(so_file):
                    raise RuntimeError("SO文件不存在且下载失败: {0}".format(so_file))
                print("下载失败，使用本地版本")
        else:
            if not os.path.exists(so_file):
                raise RuntimeError("SO文件不存在或暂无可用版本: {0}".format(so_file))
    else:
        if local_version:
            print("使用本地版本: {0}".format(local_version['version_number']))
    
    # 检查SO文件是否存在
    if not os.path.exists(so_file):
        raise RuntimeError("SO文件不存在: {0}".format(so_file))
    
    # 加载SO模块
    try:
        spec = importlib.util.spec_from_file_location("encrypted_module", so_file)
        if spec is None or spec.loader is None:
            raise RuntimeError("无法加载SO模块: {0}".format(so_file))
        
        module = importlib.util.module_from_spec(spec)
        spec.loader.exec_module(module)
        
        return module
        
    except Exception as ex:
        raise RuntimeError("加载SO模块失败: {0}".format(ex))


# 自动加载模块并执行
try:
    _module = load_so_module()
    
    # 导出入口函数
    if hasattr(_module, ENTRY_FUNCTION):
        entry_func = getattr(_module, ENTRY_FUNCTION)
        globals()[ENTRY_FUNCTION] = entry_func
        
        # 如果作为主程序运行，自动执行入口函数
        if __name__ == "__main__":
            result = entry_func()
            if result is not None:
                print("返回值:", result)
    else:
        print("警告: SO模块中未找到入口函数 '{0}'".format(ENTRY_FUNCTION))
        # 导出模块本身，允许用户手动访问
        encrypted_module = _module
        
except Exception as ex:
    print("加载器初始化失败: {0}".format(ex))
    raise
